// TS中类的主要结构：属性、构造函数、方法、存取器、访问修饰符、装饰器
// 属性类似于变量，加上相关类型标注，当然也能通过值的类型进行类型推导
// 构造函数、方法、存取器类似于函数，加上参数的类型与返回类型

// 访问修饰符：可以修饰属性和方法
// public（默认）: 可以在类、类的子类中，以及类和子类的实例对象访问
// protected: 仅能在类和子类中访问
// private: 仅能在类的内部被访问到
// # ES2022新特性，私有属性和方法

// 访问器(存取器)属性如果有set，那么默认get返回具体的类型
// 所以将本身属性可选这种写法和访问器属性get，set一起写就有逻辑冲突
class Animal {
  public name: string;
  protected color: string;
  private _age: number;
  // #type: string;
  constructor(name: string, color: string, _age: number, type: string) {
    this.name = name;
    this.color = color;
    this._age = _age;
    // this.#type = type;
  }

  get age() {
    // if (this._age === undefined) throw new Error("年龄未知");
    return this._age;
  }

  set age(value: number) {
    if (value < 0 || value > 150) throw new Error("年龄不符合规范...");
    this._age = value;
  }

  // get type(): string {
  //   return this.#type;
  // }

  // set type(value: "Cat" | "Dog") {
  //   this.#type = value;
  // }

  // 静态属性
  static kingdom = "Animal";

  // 静态方法
  static showKingdom(): string{
    console.log(Animal.kingdom);
    console.log(this.kingdom);
    // console.log(this.name);
    return `The Kingdom is ${Animal.kingdom}`
  }

  show() {
    console.log(this.name, this.color, this._age);
  }
}

/* class Animal{
  
  #type: string;
  constructor(
    public name: string,
    protected color: string,
    private _age: number,
    type: string) { 
    this.#type = type;
  }

  show() { 
    console.log(this.name, this.color, this._age)
  }
} */

class Cat extends Animal {
  info() {
    // 父类中public修饰的属性和方法在子类中都能访问
    console.log(this.name);
    this.show();
    // 父类中protected修饰的属性和方法在子类中都能访问
    console.log(this.name);
    this.show();

    // 父类中private修饰的属性和方法在子类中 不能访问
    // console.log(this._age);
  }
}

const a = new Animal("小白", "白色", 3, "Dog");
console.log(a.name);
a.show();
// a.age = -1;
// a.type = "Cat";

const s = Animal.showKingdom();
console.log(s)


// console.log(a.color);
// console.log(a._age);

const c = new Cat("小猫", "花色", 2, "Cat");
console.log(c.name);
c.info();
